<?php

class PagePlan extends BasePagePlan
{
    public function createPlan($new_plan)
    {
        $this->changePlan($new_plan, true);
        if (is_string($new_plan))
            $new_plan = Doctrine_Core::getTable('Plan')->findOneBy('name', $new_plan);
        $this->offer_id = $new_plan->subscription_offer_id;
    }


    public function activatePlan($new_plan, $from_admin=false)
    {
        $this->changePlan($new_plan, false, false, $from_admin);
    }


    public function cancelPlan($current_plan)
    {
        // TODO: store data for uncancel
        $this->changePlan('free', false, true);
    }


    public function uncancelPlan($current_plan)
    {
        // TODO: which date for expire_at?
        $this->changePlan($current_plan);
    }


    public function updateExpiresAt()
    {
        $this->changeExpiresAt();
        $this->save();
    }


    private function changeExpiresAt($is_auto_renew = true)
    {
        $request = sfContext::getInstance()->getRequest();
        // Push back to 23:59:59
        if ($request['subscription']['expires_at']) {
            $date = $request['subscription']['expires_at'];
            if (empty($date['month'])) {
                $this->expires_at = null;
            } else {
                if (mktime(23, 59, 59, $date['month'], $date['day'], $date['year']) > time())
                    $time = mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
                else
                    $time = time() + 2629743; // + 1 mois

                $this->expires_at = date(DATE_ISO8601, $time);
            }
        } else {
            $old_expires_at = time();
            if ($this->expires_at != null && strtotime($this->expires_at) < $old_expires_at && $is_auto_renew)
                $old_expires_at = strtotime($this->expires_at);

            if ($this->Plan->period === 'month')
                $this->expires_at = date(DATE_ISO8601, strtotime('+1month', $old_expires_at));
            elseif ($this->Plan->period === 'year')
                $this->expires_at = date(DATE_ISO8601, strtotime('+1year', $old_expires_at));
            elseif ($this->Plan->name === 'trial')
                $this->expires_at = date(DATE_ISO8601, strtotime('+30day', $old_expires_at));
            else
                $this->expires_at = null;
        }

        $this->save();
    }


    private function changePlan($new_plan, $is_create = false, $is_cancel = false, $from_admin=false)
    {
        if (is_string($new_plan))
            $new_plan = Doctrine_Core::getTable('Plan')->findOneBy('name', $new_plan);
        if (!$new_plan)
            throw new Exception("Invalid plan '$new_plan'");

        $old_plan = $this->Plan;

        // In case we receive both subscription_cancelled and payment_failure events
        if ($is_cancel && $old_plan->name === 'free')
            return;

        $this->Plan = $new_plan;
        if ($is_create || $old_plan->name === 'free' || $old_plan->name === 'trial')
            $this->offer_id = $new_plan->subscription_offer_id;

        $old_expires_at = $this->expires_at;
        $this->changeExpiresAt(false);

        if ($is_create)
            return;

        // Set slots and pause extra jobs if necessary
        $free_slots = $this->Page->setJobSlots($new_plan->job_slots);

        // Activate / deactive engines according to plan
        $this->Page->Profile->is_smart_sort_activated  = $new_plan->is_engines_enabled;
        $this->Page->Profile->is_smart_share_activated = $new_plan->is_engines_enabled;

        // Give extra credits on first annual subscription
        if ($this->extra_credit < 0 && $new_plan->extra_credit >= 0 && $new_plan->period === 'year') {
            $this->extra_credit = $new_plan->extra_credit;
            if ($this->extra_credit)
                $this->Page->addCredits($this->extra_credit);
        }

        // Update authorization on API
        $this->Page->ApiCredentials->updateFromPlan($new_plan);

        $is_full = ($free_slots <= 0);
        $is_over_quota = ($free_slots < 0);
        $this->Page->State->changePlanEvent($old_plan, $new_plan, $is_cancel, $is_full, $is_over_quota);
        $this->save();
        $this->logPagePlan($old_plan, $new_plan, $is_cancel, $is_full, $is_over_quota, $from_admin, $old_expires_at);
    }

    public function updatePageParent()
    {
        try {
            $plan = Doctrine_Core::getTable('Plan')->findOneBy('plan_id', $this->plan_id);
            $this->offer_id = $plan->subscription_offer_id;
            $this->save();
        } catch (Exception $e) {
        }
    }


    public static function updateTask()
    {
        $base_q = Doctrine_Query::create()
            ->from('PagePlan pp')
            ->innerJoin('pp.Page page')
            ->innerJoin('page.State state')
            ->innerJoin('pp.Plan plan');

        vtnsLog::info('Renewing expired plans...');
        $q = clone $base_q;
        $q->addWhere('plan.cost > 0')
            ->addWhere('pp.is_paypal <> 0')
            ->addWhere('pp.expires_at IS NOT NULL AND pp.expires_at < NOW()');

        foreach ($q->execute() as $page_plan) {
            $switchPlan = (bool) $page_plan->next_plan_id;
            $newPlan = $switchPlan ? $page_plan->NextPlan : $page_plan->Plan;

            vtnsLog::info(
                "  Page %d : %s plan %s - %s ($ %d)",
                $page_plan->page_id,
                $switchPlan ? 'Switch to' : 'Renew',
                $newPlan->name, $newPlan->period, $newPlan->cost);

            try {
                $page_plan->renewPlan();

                vtnsLog::info(
                    "  OK, plan expiration : %s", $page_plan->expires_at);
            } catch (Exception $e) {
                vtnsLog::criticalWithBT(
                    "  Error: %s", $e->getMessage());
            }
        }

        vtnsLog::info('Canceling expired plans...');
        $q = clone $base_q;
        $q->addWhere('pp.expires_at IS NOT NULL AND pp.expires_at < NOW()');

        foreach ($q->execute() as $page_plan) {
            vtnsLog::info(
                "  Page %d : plan %s has expired on %s",
                $page_plan->page_id,
                $page_plan->Plan->name,
                $page_plan->expires_at);

            $page_plan->cancelPlan(null);
        }
    }


    public function renewPlan()
    {
        if ($this->next_plan_id) {
            $plan = $this->NextPlan;
            $change_plan = true;
        } else {
            $plan = $this->Plan;
            $change_plan = false;
        }

        $paymentSucceeded = true;

        $conn = Doctrine_Manager::getInstance()->getConnection('doctrine');
        $conn->beginTransaction();
        if ($plan->cost > 0) {
            // Check credit card validity, we need this to create an invoice
            // since it requires a uid
            if (!$this->card_id) {
                $this->sendAdminEmail('renew-no-card');
                $conn->rollback();
                throw new Exception('The plan has no credit card');
            }
            $card = Doctrine_Core::getTable('CreditCard')->find($this->card_id);
            if (!$card) {
                $this->sendAdminEmail('renew-no-card');
                $conn->rollback();
                throw new Exception('The credit card '.$this->card_id.' does not exist');
            }

            if (strtotime($card->expires_date) < time()) {
                $this->sendAdminEmail('renew-expired-card');
                $paymentSucceeded = false;
                $paymentError = 'The credit card '.$this->card_id.' is expired ('.$card->expires_date.')';
            }

            // We now have a credit card (that might not work), create and
            // configure a payment
            // Build payment request
            $payment = new PaypalPayment();
            $payment->item = 'Renew-subscription';
            $payment->amount = (int) round($plan->cost * 100);
            $payment->page_id = $this->page_id;
            $payment->uid = $card->uid;
            $payment->payment_status = '';

            // Attempt payment
            if ($paymentSucceeded && !$payment->doDirectPayment($card, '0.0.0.0')) {
                $this->sendAdminEmail('renew-payment-failure', array(
                    'error'   => $payment->getLastErrorCode(),
                    'message' => $payment->getLastErrorMessage(),
                ));
                $paymentSucceeded = false;
                $paymentError = 'Payment failed [code '.$payment->getLastErrorCode().']: '.$payment->getLastErrorMessage();
            }

            $payment->createInvoice($plan->period, $paymentSucceeded);

            if (!$paymentSucceeded) {
                $conn->commit();
                throw new Exception($paymentError);
            }

            $payment->refundGodfather($plan->period);
        }

        if ($change_plan) {
            $this->changePlan($plan, false, false);
            $this->next_plan_id = null;
            $this->save();
        } else {
            $this->updateExpiresAt();
        }

        $conn->commit();
    }


    public function logPagePlan($old_plan, $new_plan, $is_cancel, $is_full, $is_over_quota, $from_admin=false, $old_expires_at)
    {
        try {
            if ($from_admin) {
                $this->sendAdminEmail('change-plan-from-admin', array(
                        'old_plan'         => $old_plan,
                        'new_plan'         => $new_plan,
                        'old_expires_at'   => $old_expires_at,
                        ));
            }
            LogPagePlan::log($this->page_id, $old_plan, $new_plan, $is_cancel, $is_full, $is_over_quota);
        } catch (Exception $e) {
            echo "Error adding log to LogPagePlan for page_id: {$this->page_id}, old plan: {$old_plan}, new plan: {$new_plan}\n";
        }
    }


    private function sendAdminEmail($type, $data = array())
    {
        try {
            switch ($type) {
              case 'change-plan-from-admin':
                $old_plan       = $data['old_plan'];
                $new_plan       = $data['new_plan'];
                $old_expires_at = $data['old_expires_at'] ? $data['old_expires_at'] : 'Never';
                $new_expires_at = $this->expires_at ? $this->expires_at : 'Never';
                $subject = 'Plan changed in Admin space';
                
                $body  = "Hello,<br/><br/>
                    The plan has been changed for this page:<br/>
                    Page Name = {$this->Page->Profile->name}<br/>
                    PageID = {$this->Page->page_id}<br/>
                    Link of Page: {$this->Page->Profile->link}<br/>
                    Plans informations: <br/>
                    Old Plan: {$old_plan->name}/{$old_plan->period}, Old Expires_at: {$old_expires_at} <br/>
                    New Plan: {$new_plan->name}/{$new_plan->period}, New Expires_at: {$new_expires_at} <br/>
                    Who did this: ".sfContext::getInstance()->getUser()->getFbUser()->getName()." <br/>";
                
                if ($this->extra_credit != -1) {
                    $body .= 'A free Ads credits already given ' . $this->extra_credit . '<br/>';
                }
                break;
              case 'renew-no-card':
                $subject = 'Plan renewal failure: no associated card';
                $body  = "Hello,<br/><br/>";
                $body .= "The plan {$this->Plan->name} - {$this->Plan->period} of page {$this->Page->name} ({$this->page_id})<br/>";
                $body .= "could not be renewed because there is no credit card associated to this plan.<br/><br/>";
                $body .= "An unpaid invoice was created on Freshbooks and an email sent to the client to {$this->Page->Profile->billing_email} <br/>";
                break;
              case 'renew-expired-card':
                $subject = 'Plan renewal failure: expired card';
                $body  = "Hello,<br/><br/>";
                $body .= "The plan {$this->Plan->name} - {$this->Plan->period} of page {$this->Page->name} ({$this->page_id})<br/>";
                $body .= "could not be renewed because the credit card has expired.<br/><br/>";
                $body .= "An unpaid invoice was created on Freshbooks and an email sent to the client to {$this->Page->Profile->billing_email} <br/>";
                break;
              case 'renew-payment-failure':
                $subject = 'Plan renewal failure: payment failure';
                $body  = "Hello,<br/><br/>";
                $body .= "The plan {$this->Plan->name} - {$this->Plan->period} of page {$this->Page->name} ({$this->page_id})<br/>";
                $body .= "could not be renewed because the Paypal payment failed with the following error:<br/>";
                $body .= "Error {$data['error']} &mdash; {$data['message']}<br/>";
                $body .= "An unpaid invoice was created on Freshbooks and an email sent to the client to {$this->Page->Profile->billing_email} <br/>";
                break;
              default:
                return;
            }

            $this->sendEmail($subject, $body, sfConfig::get('sf_payment_mail_to'));
        } catch (Exception $e) {
            sfContext::getInstance()->getLogger()->info("Error sending admin email '$type' : ".$e->getMessage());
        }
    }


    private function sendEmail($subject, $body, $mail_to)
    {
        $i18N = sfContext::getInstance()->getI18N();
        $old_culture = $i18N->getCulture();
        $i18N->setCulture('EN_en');
        sfContext::getInstance()->getMailer()->composeAndSendPartial(
            array(sfConfig::get('sf_payment_mail_from') => sfConfig::get('sf_payment_name_from')),
            $mail_to,
            $subject,
            'generic',
            array('content' => $body)
            );
        $i18N->setCulture($old_culture);
    }


    public function sendPaypalSyncDeactivationEmail()
    {
        $i18N = sfContext::getInstance()->getI18N();
        $old_culture = $i18N->getCulture();
        $i18N->setCulture('EN_en');
        sfContext::getInstance()->getMailer()->composeAndSendPartial(
            array(sfConfig::get('sf_billing_mail_from') => sfConfig::get('sf_billing_name_from')),
            array(sfConfig::get('sf_billing_mail_from') => sfConfig::get('sf_billing_name_from')),
            $i18N->__('Paypal Sync Deactivation'),
            'fss_paypal_sync_deactivation',
            array(
                'page_id'   => $this->page_id,
                'page_name' => $this->Page->Profile->name,
                'page_link' => $this->Page->Profile->link,
                'plan'      => $this->Plan->label.' - '.$this->Plan->period,
                )
            );
        $i18N->setCulture($old_culture);
    }
}
